package com.tsyz.servlet.controller;

import com.alibaba.fastjson2.JSON;
import com.tsyz.servlet.exception.ErrorEnumCode;
import com.tsyz.servlet.exception.ParamException;
import com.tsyz.servlet.util.ValidationUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

/**
 * 抽象控制器基类，提供通用的参数校验功能
 * 包含空值校验、容器非空校验、Jakarta Validation框架校验及入参打印
 *
 * @author ext.zhaoke14
 */
@Slf4j
public abstract class AbstractController {


    /**
     * 综合参数校验方法，执行多层级校验：
     * 1. 基础空值校验（对象为null）
     * 2. 容器类型非空校验（Collection）
     * 3. map类型非空校验（Map）
     * 4. 字符串非空校验（非空白字符串）
     * 5. Jakarta Validation注解校验（针对对象字段级规则）
     *
     * @param param 待校验的参数对象
     * @throws ParamException 当任何校验失败时抛出，包含具体错误信息
     */
    protected <T> void checkParam(T param) {
        // 1. 基础空值校验
        if (param == null) {
            throw new ParamException(ErrorEnumCode.PARAM_NULL, "请求参数不能为空");
        }

        // 2. 容器类型非空校验
        if (param instanceof Collection) {
            if (CollectionUtils.isEmpty((Collection<?>) param)) {
                throw new ParamException(ErrorEnumCode.PARAM_NULL, "集合参数不能为空");
            }

        }
        // 3. map类型非空校验
        else if (param instanceof Map) {
            if (MapUtils.isEmpty((Map<?, ?>) param)) {
                throw new ParamException(ErrorEnumCode.PARAM_NULL, "Map参数不能为空");
            }
        }
        // 4. 字符串非空校验
        else if (param instanceof String) {
            if (StringUtils.isBlank((String) param)) {
                throw new ParamException(ErrorEnumCode.PARAM_NULL, "字符串参数不能为空");
            }
        }

        // 5. 框架注解校验（支持集合元素校验）
        if (param instanceof Collection) {
            // 遍历集合元素进行校验
            ((Collection<?>) param).forEach(this::validateObject);
        } else {
            // 单个对象校验
            validateObject(param);
        }
    }


    /**
     * 使用Jakarta Validation框架对单个对象进行字段级校验
     *
     * @param object 待校验的对象（非null）
     * @throws ParamException 当校验失败时抛出，包含所有错误信息
     */
    private <T> void validateObject(T object) {
        if (object == null) {
            return;
        }

        Validator validator = ValidationUtil.getValidator();
        Set<ConstraintViolation<T>> violations = validator.validate(object);

        if (!violations.isEmpty()) {
            for (ConstraintViolation<T> violation : violations) {
                log.error("参数校验失败：{}", JSON.toJSONString(violation));
                throw new ParamException(ErrorEnumCode.PARAM_NULL, violation.getMessage());
            }
        }
    }
}
